home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Whiteline: delta
/
whiteline CD Series - delta.iso
/
tools
/
utils
/
twtcp122
/
pktdrv
/
pktdlink
/
nicdrv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-25
|
17KB
|
762 lines
/********************************************************************/
/* */
/* Packet driver for D-LINK DE600 ethernet controller */
/* */
/* Copyleft by P. Mayer, 1992 fortec - TU-Vienna IAEE */
/* All rights reserved */
/* */
/* (Pure-C) */
/********************************************************************/
#define LOCKMEM 0x1
#define LOCKALLO 0x2
#define LOCKFREE 0x4
#define LOCKMAIN 0x8
#define LOCKRES 0x10
#define LOCKREC 0x20
#define LOCKNET 0x40
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <tos.h>
#include <time.h>
#include "nicmem.h"
#include "nicdrv.h"
#include "pktqueue.h"
#include "pktdrv.h"
#include "cookie.h"
#include "inetcust.h"
#define noDEBUG
#define noDEBUGINTR
#define noDEBUGPKT
#define Bconws(x) dpy = &x;while(*dpy)(Bconout(2,*dpy++))
char str[80];
char *dpy;
PKTBUF PPKT[MAXPKT];
PKTPOOL PPOOL;
extern char locked200;
int retval;
int term = 0;
int good = 0;
et_hdr header;
int mode;
void (interrupt *ihandler)(void) = NULL;
extern void lance_interrupt(void);
extern void lance_200interrupt(void);
extern long *old200;
int resetNIC(void); /* reset lance, init datastructures */
PKTPOOL *p_free; /* queue of free packets */
u_short freecnt; /* number of free packets */
procref ext_tab[8] = /* subfunction table */
{
net_reset,
net_open,
net_release,
net_send,
net_getadr,
net_info,
(procref)net_pktalloc,
net_pktfree
};
PROTOCOL protos[MAXPROTOCOLS]; /* protocols to serve */
int protocols = 0; /* number of active protocols */
et_stat stat; /* statistics block */
/*************************************************************
test for de600 ethernetadapter interface on cartridge port
*************************************************************/
#define NIC_BASE 0xfa0000L
typedef unsigned char byte;
byte CurTxPage, Mode_RxPg;
int RxPktLen, RxStartAdd, TxStartAdd, CurRxPage, our_type;
byte our_address[6];
int last, LastTxStartAdd;
#define WRITE (0x00 << 1)
#define READ (0x01 << 1)
#define STATUS (0x02 << 1)
#define COMMAND (0x03 << 1)
#define NUL_CMD (0x0c << 1)
#define RX_LEN (0x05 << 1)
#define TX_ADR (0x06 << 1)
#define RW_ADR (0x07 << 1)
#define WRITE_STROBE (0x08 << 1)
#define RXEN (0x08)
#define TXEN (0x04)
#define LOOPBACK (0x0c)
#define RX_NONE (0x00)
#define RX_ALL (0x01)
#define RX_BP (0x02)
#define RX_MBP (0x03)
#define RESET (0x80)
#define STOP_RESET (0x00)
#define RXBUSY 0x80
#define GOOD 0x40
#define RESET_FLAG 0x20
#define T16 0x10
#define TXBUSY 0x08
#define BFRSIZ 2048
#define RUNT 60
#define EADDR_LEN 6
#define HA13 0x20
#define PAGE_0 0x00
#define PAGE_1 0x08
#define PAGE_2 0x10
#define PAGE_3 0x18
#define delay() /* no delay needed for ST */
#define pause()
/* defines for access to DE600 */
#define WRITE_SUB_FAST(value, cmd) \
x = *(int*)(base + (int)(((((int)value) << 5) & 0x1e0) + cmd)); \
x = *(int*)(base + (int)(last = (((((int)value) << 1) & 0x1e0) + ((cmd) ^ WRITE_STROBE)))); \
#define WRITE_SUB(value, cmd) \
x = *(int*)(base + (int)(((((int)value) << 5) & 0x1e0) + cmd | WRITE_STROBE)); \
delay(); \
x = *(int*)(base + (int)(((((int)value) << 5) & 0x1e0) + cmd)); \
delay(); \
x = *(int*)(base + (int)(((((int)value) << 1) & 0x1e0) + cmd)); \
delay(); \
x = *(int*)(base + (int)(last = ((((int)value) << 1) & 0x1e0) + cmd | WRITE_STROBE)); \
#define WRITE_SUPER_FAST(value, cmd) \
x = *(int*)(base + (int)(((((int)value) << 5)) + cmd)); \
x = *(int*)(base + (int)((((((int)value) << 1) & 0x1e0) + ((cmd) ^ WRITE_STROBE)))); \
#define READ_SUB(cmd) \
x = *(int*)(base + (int)(cmd | WRITE_STROBE)); \
delay(); \
x = *(int*)(base + (int)(cmd)); \
delay(); \
y = (*(int*)(base + (int)(cmd)) & 0xf0) ^ 0x80; \
x = *(int*)(base + (cmd | WRITE_STROBE)); \
delay(); \
y = (y >> 4) | ((*(int*)(base + (int)(last = (cmd | WRITE_STROBE))) & 0xf0) ^ 0x80); \
#define READ_STAT1 \
x = *(int*)(base + (int)STATUS); \
pause(); \
y = (*(int*)(base + (int)(STATUS))) ^ 0x80; \
x = *(int*)(base + (int)NUL_CMD); \
#define READ_STAT_FAST \
x = *(int*)(base + (int)STATUS); \
pause(); \
y = (*(int*)(base + (int)(STATUS))) ^ 0x80; \
#define READ_STAT(cmd) \
x = *(int*)(base + (int)(cmd | WRITE_STROBE)); \
delay(); \
x = *(int*)(base + (int)(cmd)); \
delay(); \
y = (*(int*)(base + (int)(cmd)) & 0xf0) ^ 0x80; \
x = *(int*)(base + (int)(NUL_CMD + WRITE_STROBE)); \
delay(); \
x = *(int*)(base + (int)(last = NUL_CMD)); \
delay(); \
#define READ_SUB_FAST(cmd) \
x = *(int*)(base + (int)(cmd)); \
x = (*(int*)(base + (int)(cmd))) & 0xf0; \
x >>= 4; \
y = *(int*)(base + (int)(cmd + WRITE_STROBE)); \
y = (((*(int*)(base + (cmd | WRITE_STROBE)) & 0xf0)) | x); \
y ^= 0x88; \
#define READ_SUPER_FAST(cmd) \
/* x = *(int*)(base + (int)(cmd));*/ \
x = (*(int*)(base + (int)(cmd))) & 0xf0; \
x >>= 4; \
/* y = *(int*)(base + (int)(cmd + WRITE_STROBE));*/ \
y = (((*(int*)(base + (cmd | WRITE_STROBE)) & 0xf0)) | x); \
y ^= 0x88; \
#define READ_HYPER_FAST(cmd) \
x = (*(int*)(base + (int)(cmd))) & 0xf0; \
x >>= 4; \
y = (((*(int*)(base + (cmd | WRITE_STROBE)) & 0xf0)) | x); \
y ^= 0x88; \
int copyEAD()
{
register byte *base = (byte*)NIC_BASE;
register int x,y;
int i;
WRITE_SUB_FAST(0,RW_ADR);
WRITE_SUB_FAST(HA13,RW_ADR);
for(i = 0; i < EADDR_LEN;i++)
{
READ_SUB_FAST(READ);
our_address[i] = y;
}
if( our_address[0] == 0x00
&& our_address[1] == 0xde
&& our_address[2] == 0x15)
{
our_address[1] = 0x80;
our_address[2] = 0xc8;
/* our_address[3] &= 0x0f;
our_address[3] |= 0x70; */
}
else
{
return -1;
}
WRITE_SUB_FAST(0,RW_ADR);
WRITE_SUB_FAST(HA13,RW_ADR);
for(i = 0;i < EADDR_LEN;i++)
{
WRITE_SUB_FAST(our_address[i],WRITE);
}
x++;
return 0;
}
int Check_DE600()
{
register byte *base = (byte*)NIC_BASE;
register int x,y;
x = *(int*)(base + NUL_CMD);
delay();
WRITE_SUB(RESET,COMMAND);
delay();
WRITE_SUB(STOP_RESET,COMMAND);
delay();
READ_STAT(STATUS);
x++;
if(y == 0) return 0;
else return -1;
}
int send_packet(byte *p_pkt, int pkt_len)
{
register byte *base = (byte*)NIC_BASE;
register int x,y,TxStartAdd,val;
int loop_cnt;
void lnc_check(void);
if(pkt_len < RUNT) pkt_len = RUNT;
pkt_len = (pkt_len+1) & ~1; /* make sure min. size */
CurTxPage ^= 0x8; /* next free buffer */
TxStartAdd = (BFRSIZ - pkt_len) | ((int)CurTxPage << 8);
WRITE_SUB_FAST(TxStartAdd & 0xff, RW_ADR);
WRITE_SUB_FAST(TxStartAdd >> 8, RW_ADR);
while(pkt_len--)
{
val = *p_pkt++;
WRITE_SUPER_FAST(val,WRITE);
}
last = ( ( ( (int)(*(p_pkt-1)) << 1) & 0x1e0) + ((WRITE) ^ WRITE_STROBE));
for(loop_cnt = 0x4000;loop_cnt--;)
{
y = (*(int*)(base + (int)last)) ^ 0x80;
if((y & TXBUSY) == 0) break;
}
LastTxStartAdd = TxStartAdd;
WRITE_SUB_FAST(TxStartAdd & 0xff, TX_ADR);
WRITE_SUB_FAST(TxStartAdd >> 8, TX_ADR);
WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND);
WRITE_SUB_FAST(Mode_RxPg | RXEN | TXEN, COMMAND);
mode = TXEN | RXEN;
x++;
return pkt_len;
}
int test_mem()
{
register byte *base = (byte*)NIC_BASE;
register int x,y,i;
locked200 |= LOCKMEM;
WRITE_SUB_FAST(0,RW_ADR);
WRITE_SUB_FAST(0,RW_ADR);
for(i = 0;i < 0x800;i++)
{
WRITE_SUB_FAST(i & 0xff,WRITE);
}
WRITE_SUB_FAST(0,RW_ADR);
WRITE_SUB_FAST(0,RW_ADR);
for(i=0;i<0x800;i++)
{
READ_SUB_FAST(READ);
if((i & 0xff) != y)
{
Cconws("\r\nDE600 memory test error!!\r\n");
locked200 &= ~LOCKMEM;
return -1;
}
}
x++;
locked200 &= ~LOCKMEM;
return 0;
}
int resetNIC(void)
{
int copyEAD(void);
int Check_DE600(void);
int test_mem(void);
void enable_rcv(void);
CurRxPage = 0x20;
Mode_RxPg = RX_BP | 0x20;
CurTxPage = 0;
if(Check_DE600()) return -1;
if(test_mem()) return -1;
if(copyEAD()) return -1;
enable_rcv();
return 0;
}
void stopNIC(void)
{
register byte *base = (byte*)NIC_BASE;
register int x;
WRITE_SUB_FAST(Mode_RxPg, COMMAND);
x++;
}
byte NICstatus()
{
register byte *base = (byte*)NIC_BASE;
register int x,y;
READ_STAT1;
x++;
return y;
}
void enable_rcv()
{
register byte *base = (byte*)NIC_BASE;
register int x;
WRITE_SUB_FAST(Mode_RxPg, COMMAND);
WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND);
mode = RXEN;
x++;
}
int read_inf(void)
{
COOKIE *cookie;
cookie = get_cookie(INETCUSTCOOKIE);
if(!cookie || !cookie->val) return(0);
return(1);
}
int net_info(int len, char *buf)
{
locked200 |= LOCKNET;
if(!buf)
{
Mode_RxPg = (Mode_RxPg & 0xfc) | len;
locked200 &= ~LOCKNET;
return(0);
}
if(buf == (char *)1L)
{
resetNIC();
locked200 &= ~LOCKNET;
return(0);
}
stat.st_free = freecnt;
memcpy(buf,(char *)&stat,(size_t)len<sizeof(stat)?len:(int)sizeof(stat));
locked200 &= ~LOCKNET;
return(len);
}
int net_open(int type, int (*handler)(int,char *))
{
int i,new;
if(!handler) return(EPARAM);
if(protocols >= MAXPROTOCOLS) return(EPROTAVAIL);
new = -1;
locked200 |= LOCKNET;
if(!protocols)
{
if(net_reset() < 0)
{
locked200 &= ~LOCKNET;
return(EINIT);
}
}
for(i = 0; i < MAXPROTOCOLS; i++)
{
/* protocol already used */
if(protos[i].type == type)
{
locked200 &= ~LOCKNET;
return(EPROTUSED);
}
if(protos[i].type == ET_UNUSED && new<0 ) new = i; /* find first free entry */
}
if(new < 0) new = protocols;
protocols++;
protos[new].handler = handler;
protos[new].recvd = 0;
protos[new].sent = 0;
protos[new].type = type;
locked200 &= ~LOCKNET;
return(new);
}
int net_release(int type)
{
int i;
void stopNIC(void);
if(!protocols) return(EPROTUSED);
if(type == ET_UNUSED) return(EPROTUSED);
for(i=0; i < MAXPROTOCOLS; i++)
if(protos[i].type == type) break;
if(i==MAXPROTOCOLS)
{
return(EPROTUSED);
}
locked200 |= LOCKNET;
protocols--;
if(!protocols)
{
stopNIC();
}
protos[i].type = ET_UNUSED;
protos[i].handler = NULL;
locked200 &= ~LOCKNET;
return(protocols);
}
int net_send(int len, char *buf)
{
register byte *base = (byte*)NIC_BASE;
register long timeout;
register int y;
void lnc_check(void);
byte NICstatus(void);
void enable_rcv(void);
#ifdef DEBI
printf("netsend %lx length %d good = %d mode = %x\n",buf,len,good,mode);
#endif
if(!buf || !len || (buf < (char *)PPKT) || (buf > (char *)&PPOOL)) return(EPARAM);
if(len < 60) len = 60;
if(len > (int)sizeof(PACKET)) return(EPKTLEN);
locked200 |= LOCKNET;
timeout = clock() + 3*TIMEOUT;
len = send_packet((byte*)buf,len);
#ifdef DEBI
printf("send done\n");
#endif
locked200 &= ~LOCKNET;
return(0);
}
int net_getadr(int len, char *buf)
{
if(len >= (int)sizeof(HADDR))
{
buf[0] = our_address[0];
buf[1] = our_address[1];
buf[2] = our_address[2];
buf[3] = our_address[3];
buf[4] = our_address[4];
buf[5] = our_address[5];
return((int)sizeof(HADDR));
}
return(0);
}
int net_reset(void)
{
int i,tmp;
locked200 |= LOCKRES;
for(i=0;i<MAXPROTOCOLS;i++) /* init protocol table */
{
protos[i].type = ET_UNUSED;
protos[i].handler = NULL;
protos[i].recvd = 0;
protos[i].sent = 0;
}
protocols = 0;
p_free = p_init(MAXPKT,&PPOOL,PPKT); /* init free packets */
freecnt = MAXPKT;
tmp = resetNIC();
locked200 &= ~LOCKRES;
return tmp;
}
PKTBUF *net_pktalloc(protocol)
u_short protocol;
{
PKTBUF * tmp;
if(!p_free) net_reset();
locked200 |= LOCKALLO;
if(freecnt <= 1)
{
Bconws("DLINKDRV: No free Packet\r");
locked200 &= ~LOCKALLO;
return(NULL);
}
freecnt--;
tmp = ap_getpkt(protocol,p_free);
#ifdef DEBUGPKT
sprintf(str,"netpktalloc at %lx\r",tmp);
Bconws(str);
#endif
locked200 &= ~LOCKALLO;
return tmp;
}
int net_pktfree(p_pkt)
PKTBUF *p_pkt;
{
locked200 |= LOCKFREE;
#ifdef DEBUGPKT
sprintf(str,"netpktfree at %lx\r",p_pkt);
Bconws(str);
#endif
if(!p_free || !p_pkt || (p_pkt < PPKT) || (p_pkt > &PPKT[MAXPKT-1]))
{
Bconws("DLINKDRV: Packet out of bounds\r");
locked200 &= ~LOCKFREE;
return(FALSE);
}
if(((long)p_pkt - (long)PPKT) % sizeof(PKTBUF))
{
Bconws("DLINKDRV: Packet misaligned\r");
locked200 &= ~LOCKFREE;
return(FALSE);
}
if(ap_putpkt(p_free,p_pkt))
{
freecnt++;
locked200 &= ~LOCKFREE;
return(TRUE);
}
Bconws("DLINKDRV: Packet not freed\r");
locked200 &= ~LOCKFREE;
return(FALSE);
}
/*******************************************************************/
/* read D-LINK function */
/*******************************************************************/
void lnc_check(void)
{
register byte *base = (byte*)NIC_BASE;
register int x,y,i,ii,NICstate;
int type, RxPktLen, loop;
et_stat *et_stat;
PKTBUF *pkt;
byte * pb;
locked200 |= LOCKREC;
for(loop = 0;loop < 1;loop++)
{
x = *(int*)(base + (int)STATUS);
y = *(int*)(base + (int)STATUS);
x = *(int*)(base + (int)NUL_CMD);
NICstate = y;
if(NICstate & GOOD)
{
READ_SUPER_FAST(RX_LEN);
RxPktLen = y;
READ_SUPER_FAST(RX_LEN);
RxPktLen += (y << 8);
Mode_RxPg ^= 0x10;
WRITE_SUB_FAST(Mode_RxPg, COMMAND);
WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND);
mode = RXEN;
WRITE_SUB_FAST(0,RW_ADR);
WRITE_SUB_FAST(CurRxPage >> 1,RW_ADR);
CurRxPage ^= 0x10;
RxPktLen -= 4;
et_stat = &stat;
et_stat->st_err = NICstate;
et_stat->st_intr++;
pb = (byte*)&header;
for(i=0; i < 14;i++)
{
READ_SUPER_FAST(READ);
*pb++ = y;
}
type = header.et_type;
et_stat->st_received++;
if(header.et_dest[0] != 0xff)
{
for(i = 0;i < MAXPROTOCOLS; i++)
{
if(protos[i].type == type)
{
/* must have one packet free */
if((pkt = ap_getpkt(type,p_free)) != 0)
{
freecnt--;
memcpy((char*)pkt,(char*)&header,sizeof(et_hdr));
pb = pkt->et_data;
for(ii=(int)sizeof(et_hdr); ii < RxPktLen; ii++)
{
READ_SUPER_FAST(READ);
*pb++ = y;
}
if(protos[i].handler)
{
if(protos[i].handler(RxPktLen,(char *)pkt))
{
et_stat->st_got++;
protos[i].recvd++;
}
}
else
{
/* free unused packet */
if(ap_putpkt(p_free,pkt)) freecnt++;
break;
}
}
}
}
}
}
else
{
WRITE_SUB_FAST(Mode_RxPg, COMMAND);
WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND);
if(loop == 0) break;
}
if(NICstate & T16)
{
et_stat->st_xmiterr++;
}
}
x++;
locked200 &= ~LOCKREC;
}
int main()
{
COOKIE *cookie;
int (*call)(void);
long lance_install(void);
Cconws("\r\nPacket driver V1.1 for Dlink DE600 ");
cookie = get_cookie(PKTCOOKIE);
if(cookie)
{
(long)call = ((long *)cookie->val)[NETRESET];
if(call() == 0) /* reset network */
Cconws("\r\nexisting driver reset\r\n");
else
Cconws("\r\ncould not reset existing driver\r\n");
return 0;
}
if(!read_inf())
{
Cconws("INETCUST not installed !!\r\n");
return 1;
}
else
{
if(net_reset() < 0)
{
Cconws("\r\nno DE600 detected !!\r\n");
return 1;
}
locked200 |= LOCKMAIN;
if((int)Supexec(lance_install) < 0)
{
Cconws("\r\ncould not install handler !!\n");
return 1;
}
add_cookie(PKTCOOKIE,(long)ext_tab);
Cconws("installed\r\n(c) pm FORTec 1992\r\n");
locked200 &= ~LOCKMAIN;
Ptermres(_PgmSize,0);
}
return 0;
}
long lance_install()
{
void lnc_check(void);
/* long **vblqueue = *(long***)0x456L;
int vblnum = *(int*)0x454L;
int i;
for(i=1; i< vblnum;i++) if (*(vblqueue+i) == 0L) break;
if(i< vblnum)
{
*(vblqueue+i) = (long*)lance_interrupt;
ihandler = (void (interrupt *)())lnc_check;
return 0;
}
else return -1;
*/
old200 = (long*)Setexc(69,lance_200interrupt);
ihandler = (void (interrupt *)())lnc_check;
/* old200 = *(long*)0x400;
*(long*)0x400 = (long)lance_200interrupt;*/
return 0;
}